package Kernel;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.*;

import GUI_Element.ShapeTransition;

public class Transition extends Thread{
	
	static List<Transition> TransitionSet = new ArrayList<Transition>();
	
	public int TransitionIndex;
	private ShapeTransition t;
	
	AbstractSet<Arc_P2T> PreArcSet = new HashSet<Arc_P2T>();
	AbstractSet<Arc_T2P> PostArcSet = new HashSet<Arc_T2P>();
	
	private static int MinWaitingTime = 500;
	private static int MaxWaitingTime = 1000;
	
	private boolean stop = false;
	static long FireCount = 0;
	private boolean oneStep = false;
	static private long CountMark;
	
	public Transition(ShapeTransition t) {
		super();
		TransitionSet.add(this);
		TransitionIndex = TransitionSet.indexOf(this)+1;
		this.t = t;
	}
	public Transition(ObjectInputStream ois, ShapeTransition t) {
		super();
		TransitionSet.add(this);
		TransitionIndex = TransitionSet.indexOf(this)+1;	
		this.t=t;
	}
	public void run() {
		while (true){
			Check_And_Do();
			Random rand = new Random();
			try {
				int temp = rand.nextInt(MaxWaitingTime-MinWaitingTime)+ 1;
				//System.out.println("Sleep " + temp + " millis and then retry.");
				sleep(MinWaitingTime);
				t.SetHappening(false);
				sleep(temp);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	private synchronized void Check_And_Do() {
		if (!Check_Condition()) {
			return;
		}
		t.SetHappening(true);
		for (Arc_P2T temp : this.PreArcSet)
			temp.Fire();
		for (Arc_T2P temp : this.PostArcSet)
			temp.Fire();
		++FireCount;
	}
	private boolean Check_Condition() {
		if (stop)
			return false;
		for(Arc_P2T temp : this.PreArcSet) {
			if ( !temp.Check_State() )
				return false;
		}
		for(Arc_T2P temp : this.PostArcSet) {
			if ( !temp.Check_State() )
				return false;
		}
		if ( oneStep  ) {
			stop = true;
			oneStep = false;
			if ( FireCount > CountMark )
				return false;
		}
		return true;
	}
	
	public void AddPreArc(Arc_P2T preArc){
		this.PreArcSet.add(preArc);
	}
	public void AddPostArc(Arc_T2P postArc) {
		this.PostArcSet.add(postArc);
	}
	public void RemovePreArc(Arc_P2T preArc){
		this.PreArcSet.remove(preArc);
	}
	public void RemovePostArc(Arc_T2P postArc){
		this.PostArcSet.remove(postArc);
	}
	
	public void SetStop(boolean s) {
		this.stop = s;
	}
	public void OneStep() {
		oneStep = true;
		CountMark = FireCount;
		if (this.getState() == State.NEW)
			start();
		else 
			stop = false;
	}
	public void InvalidateOneStep() {
		oneStep = false;
	}
	public static void SetInterval(int min, int max){
		MinWaitingTime = min;
		MaxWaitingTime = max;
	}
	public static int GetMinWaitingTime(){
		return MinWaitingTime;
	}
	public static int GetMaxWaitingTime(){
		return MaxWaitingTime;
	}
	
	AbstractSet<Arc_P2T> GetPreArcSet(){
		return PreArcSet;
	}
	AbstractSet<Arc_T2P> GetPostArcSet(){
		return PostArcSet;
	}
	public void Store(ObjectOutputStream oos){}
}
